package com.echo.fm.platform.database;

import com.echo.util.ErrorCode;
import com.echo.util.ErrorException;
import com.echo.util.SystemWebConstant;
import org.hibernate.*;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

public class DAOHibernatePersistenceImpl implements IHibernatePersistence {

	private SessionFactory sessionFactory;

	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

	public Session openSession() throws ErrorException {
		try {
			Session session = sessionFactory.openSession();
			return session;
		} catch (HibernateException ex) {
			ex.printStackTrace();
			throw new ErrorException(ErrorCode.INTERNAL_SERVER_ERROR);
		}
	}

	public List<? extends Object> pagesList(Class<?> clazz, List<Criterion> criterions, Order order, int firstResult)
			throws ErrorException {
		return pagesList(clazz, criterions, order, firstResult, SystemWebConstant.DEFAULT_PAGE_SIZE);
	}

	public List<? extends Object> pagesList(Class<?> clazz, List<Criterion> criterions, List<Order> orders,
			int firstResult) throws ErrorException {
		return searchListByOrders(clazz, criterions, orders, firstResult, SystemWebConstant.DEFAULT_PAGE_SIZE);
	}

	public List<? extends Object> pagesList(Class<?> clazz, List<Criterion> criterions, Order order, int firstResult,
			int maxResults) throws ErrorException {
		return searchList(clazz, criterions, order, firstResult, maxResults);
	}

	public int pagesCount(Class<?> clazz, List<Criterion> criterions) throws ErrorException {
		initCriterion(criterions);
		Session session = null;
		try {
			session = openSession();
			Criteria criteria = session.createCriteria(clazz);
			loadCreterions(criteria, criterions);
			long count = (Long) criteria.setProjection(Projections.rowCount()).uniqueResult();
			return (int) count;
		} catch (HibernateException ex) {
			ex.printStackTrace();
			throw new ErrorException(ErrorCode.INTERNAL_SERVER_ERROR);
		} finally {
			closeSession(session);
		}
	}

	public List<? extends Object> searchList(Class<?> clazz, List<Criterion> criterions) throws ErrorException {
		return searchList(clazz, criterions, null, null, null);
	}

	public List<? extends Object> searchList(Class<?> clazz, List<Criterion> criterions, Order order)
			throws ErrorException {
		return searchList(clazz, criterions, order, null, null);
	}

	public List<? extends Object> searchList(Class<?> clazz, List<Criterion> criterions, Order order,
			Integer maxResults) throws ErrorException {
		return searchList(clazz, criterions, order, 0, maxResults);
	}

	@SuppressWarnings("unchecked")
	public List<? extends Object> searchList(Class<?> clazz, List<Criterion> criterions, Order order,
			Integer firstResult, Integer maxResults) throws ErrorException {
		initCriterion(criterions);
		Session session = null;
		try {
			session = openSession();
			Criteria criteria = session.createCriteria(clazz);
			loadCreterions(criteria, criterions);
			if (order != null) {
				criteria.addOrder(order);
			}
			if (firstResult != null) {
				criteria.setFirstResult(firstResult);
			}
			if (maxResults != null) {
				criteria.setMaxResults(maxResults);
			}
			return criteria.list();
		} catch (HibernateException ex) {
			ex.printStackTrace();
			// throw new ErrorException(ErrorCode.INTERNAL_SERVER_ERROR);
		} finally {
			closeSession(session);
		}
		return criterions;
	}

	public List<? extends Object> searchListByOrders(Class<?> clazz, List<Criterion> criterions, List<Order> orders,
			Integer firstResult, Integer maxResults) throws ErrorException {
		initCriterion(criterions);
		Session session = null;
		try {
			session = openSession();
			Criteria criteria = session.createCriteria(clazz);
			loadCreterions(criteria, criterions);
			if (orders != null && orders.size() > 0) {
				for (Order order : orders) {
					criteria.addOrder(order);
				}
			}
			if (firstResult != null) {
				criteria.setFirstResult(firstResult);
			}
			if (maxResults != null) {
				criteria.setMaxResults(maxResults);
			}
			return criteria.list();
		} catch (HibernateException ex) {
			ex.printStackTrace();
			throw new ErrorException(ErrorCode.INTERNAL_SERVER_ERROR);
		} finally {
			closeSession(session);
		}
	}

	public Object searchByUniqueCriterion(Class<?> clazz, List<Criterion> criterions) throws ErrorException {
		Session session = null;
		try {
			session = openSession();
			Criteria criteria = session.createCriteria(clazz);
			if (criterions != null) {
				for (Criterion criterion : criterions) {
					criteria.add(criterion);
				}
			}
			return criteria.uniqueResult();
		} catch (HibernateException ex) {
			ex.printStackTrace();
			throw new ErrorException(ErrorCode.INTERNAL_SERVER_ERROR);
		} finally {
			closeSession(session);
		}
	}

	public Object searchByUniqueCriterion(Class<?> clazz, Criterion criterion) throws ErrorException {
		Session session = null;
		try {
			session = openSession();
			Criteria criteria = session.createCriteria(clazz);
			criteria.add(criterion);
			return criteria.uniqueResult();
		} catch (HibernateException ex) {
			ex.printStackTrace();
			throw new ErrorException(ErrorCode.INTERNAL_SERVER_ERROR);
		} finally {
			closeSession(session);
		}
	}

	@SuppressWarnings("unchecked")
	public List<? extends Object> searchByCriterion(Class<?> clazz, Criterion criterion, Order order)
			throws ErrorException {
		Session session = null;
		try {
			session = openSession();
			Criteria criteria = session.createCriteria(clazz);
			criteria.add(criterion);
			criteria.addOrder(order);
			return criteria.list();
		} catch (HibernateException ex) {
			ex.printStackTrace();
			throw new ErrorException(ErrorCode.INTERNAL_SERVER_ERROR);
		} finally {
			closeSession(session);
		}
	}

	public Serializable create(Object object) throws ErrorException {
		Session session = null;
		Transaction tx = null;
		try {
			session = openSession();
			tx = session.beginTransaction();
			Serializable result = session.save(object);
			tx.commit();
			return result;
		} catch (HibernateException ex) {
			tx.rollback();
			ex.printStackTrace();
			throw new ErrorException(ErrorCode.INTERNAL_SERVER_ERROR);
		} finally {
			closeSession(session);
		}
	}

	public void update(Object object) throws ErrorException {
		Session session = null;
		Transaction tx = null;
		try {
			session = openSession();
			tx = session.beginTransaction();
			session.saveOrUpdate(object);
			tx.commit();
		} catch (HibernateException ex) {
			tx.rollback();
			ex.printStackTrace();
			throw new ErrorException(ErrorCode.INTERNAL_SERVER_ERROR);
		} finally {
			closeSession(session);
		}
	}

	public void delete(Object object) throws ErrorException {
		Session session = null;
		Transaction tx = null;
		try {
			session = openSession();
			tx = session.beginTransaction();
			session.delete(object);
			tx.commit();
		} catch (HibernateException e) {
			tx.rollback();
			throw new ErrorException(ErrorCode.INTERNAL_SERVER_ERROR);
		} finally {
			closeSession(session);
		}
	}

	public void deletewithSQL(String sql) throws ErrorException {
		Session session = null;
		Transaction tx = null;
		try {
			session = openSession();
			tx = session.beginTransaction();
			SQLQuery q = session.createSQLQuery(sql);
			q.executeUpdate();
			tx.commit();
		} catch (HibernateException e) {
			tx.rollback();
			throw new ErrorException(ErrorCode.INTERNAL_SERVER_ERROR);
		} finally {
			closeSession(session);
		}
	}

	public void closeSession(Session session) throws ErrorException {
		if (session != null) {
			try {
				session.close();
			} catch (HibernateException ex) {
				ex.printStackTrace();
				throw new ErrorException(ErrorCode.INTERNAL_SERVER_ERROR);
			}
		}
	}

	public List<Criterion> initCriterion(List<Criterion> criterions) {
		if (criterions == null) {
			criterions = new ArrayList<Criterion>();
		}
		return criterions;
	}

	public void loadCreterions(Criteria criteria, List<Criterion> criterions) {

		if (criterions != null) {
			for (Criterion criterion : criterions) {
				criteria.add(criterion);
			}
		}
	}

	public String searchCurrSeq(String seqname) throws ErrorException {
		Session session = null;
		try {
			session = openSession();
			String id = session.createSQLQuery("SELECT nextval('" + seqname + "')").uniqueResult().toString();
			return id;
		} catch (HibernateException e) {
			throw new ErrorException(ErrorCode.INTERNAL_SERVER_ERROR);
		} finally {
			closeSession(session);
		}
	}

	public Object searchById(Class<?> clazz, Criterion criterion) throws ErrorException {
		return searchByUniqueCriterion(clazz, criterion);
	}

	public void save(Object object) throws ErrorException {
		Session session = null;
		Transaction tx = null;
		try {
			session = openSession();
			tx = session.beginTransaction();
			session.saveOrUpdate(object);
			tx.commit();
		} catch (HibernateException e) {
			tx.rollback();
			throw new ErrorException(ErrorCode.INTERNAL_SERVER_ERROR);
		} finally {
			closeSession(session);
		}
	}

}
